package com.lingjtx.auth.handle;

import com.alibaba.fastjson2.JSON;
import com.lingjtx.auth.dao.DevUserInfoMapper;
import com.lingjtx.auth.dao.DevUserLoginLogMapper;
import com.lingjtx.auth.dao.UserMapper;
import com.lingjtx.auth.entity.DevCompany;
import com.lingjtx.auth.entity.DevUserLoginLog;
import com.lingjtx.common.core.constant.Const;
import com.lingjtx.common.core.constant.RedisConfig;
import com.lingjtx.common.core.constant.ResponseTip;
import com.lingjtx.common.core.exception.HasMustCompanyException;
import com.lingjtx.common.core.exception.ResponseErrorException;
import com.lingjtx.common.core.handle.ObjectPool;
import com.lingjtx.common.core.token.AuthToken;
import com.lingjtx.common.core.token.LoginMode;
import com.lingjtx.common.core.token.UserDetail;
import com.lingjtx.common.core.token.UserVo;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.ip.IPUtils;
import com.lingjtx.common.redis.service.IRedisService;
import com.lingjtx.common.security.model.LoginPo;
import com.lingjtx.common.thread.pooling.ObjectPoolTemplate;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.net.http.HttpClient;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
public class DeveloperAuthService implements AuthHandle {

    private final ObjectPoolTemplate<HttpClient> httpObjectPoolTemplate;
    private final IRedisService redisService;
    private final DevUserLoginLogMapper userLoginLogMapper;
    private final DevUserInfoMapper userInfoMapper;
    private final UserMapper userMapper;

    public DeveloperAuthService(@Qualifier("httpObjectPoolTemplate") ObjectPoolTemplate<HttpClient> httpObjectPoolTemplate,
                                IRedisService redisService, DevUserLoginLogMapper userLoginLogMapper,
                                DevUserInfoMapper userInfoMapper, UserMapper userMapper) {
        this.httpObjectPoolTemplate = httpObjectPoolTemplate;
        this.redisService = redisService;
        this.userLoginLogMapper = userLoginLogMapper;
        this.userInfoMapper = userInfoMapper;
        this.userMapper = userMapper;
    }

    @Override
    public String getUserType() {
        return Const.UserType.DEVELOPER;
    }

    @Override
    public UserVo selectUserByIdentifier(String identifier) {
        return userMapper.selectUserByIdentifier(identifier, getUserType());
    }

    @Override
    public void register(LoginMode model, LoginPo loginPo, UserVo user, HttpServletRequest request) {
        if (LoginMode.REFRESH_TOKEN.equals(model)) {
            // 加入权限相关更新
            String token = request.getHeader(Const.AuthTokenMap.AUTHORIZATION);
            UserDetail userDetail = AuthToken.getUser(token);
            if (Objects.nonNull(userDetail)) {
                loginPo.setCompanyId(userDetail.getCompanyId());
                setPerms(userDetail.getUserId(), loginPo);
            }
            return;
        }

        if (Objects.isNull(user)) {
            throw new ResponseErrorException(ResponseTip.RESPONSE_TIP_LOGIN_FAIL);
        } else {
            // 如果绑定多个组织，返回一个组织列表给用户选择
            // 选择的公司companyId，跟随参数一起传入
            List<DevCompany> list = userInfoMapper.selectCompanyListByUserId(user.getUserId());
            if (StringUtil.isNotEmpty(list)) {
                if (list.size() == 1) { // 只加入一个组织/公司
                    Long companyId = list.getFirst().getCompanyId();
                    loginPo.setCompanyId(companyId);
                } else {
                    if (Objects.isNull(loginPo.getCompanyId())) {
                        throw new HasMustCompanyException(list);
                    }
                }
                // 绑定权限相关操作
                setPerms(user.getUserId(), loginPo);

                // 插入一条登录日志
                insertLoginLog(request, user.getUserId(), loginPo);
            }
        }
    }

    @Override
    public ObjectPool<HttpClient> getObjectPool() {
        return httpObjectPoolTemplate;
    }

    @Override
    public void insertLoginLog(HttpServletRequest request, Long userId, LoginPo loginPo) {
        String ip = request.getHeader("x-real-ip");
        if (userId == null) { // 退出登录
            String token = request.getHeader(Const.AuthTokenMap.AUTHORIZATION);
            UserDetail user = AuthToken.getUser(token);
            if (user != null) {
                DevUserLoginLog loginLog = userLoginLogMapper.selectLastLoginLog(user.getUserId());
                if (loginLog != null) {
                    loginLog.setLoginStatus(Const.LoginStatus.LOGOUT);
                    insertDatabase(ip, loginLog);
                }
            }
        } else { // 登录
            DevUserLoginLog loginLog = new DevUserLoginLog();
            loginLog.setUserId(userId);
            loginLog.setLoginStatus(Const.LoginStatus.LOGIN);
            loginLog.setDeviceModel(loginPo.getDeviceModel());
            loginLog.setDeviceUid(loginPo.getDeviceUid());
            loginLog.setOperationDevice(loginPo.getOperationDevice());
            loginLog.setCreateTime(new Date());
            redisService.set(RedisConfig.KEY_LOGIN_LOG + userId,
                    JSON.toJSONString(loginLog),
                    RedisConfig.TIMEOUT_REFRESH_TOKEN);
            insertDatabase(ip, loginLog);
        }
    }

    private void insertDatabase(String ip, DevUserLoginLog loginLog) {
        loginLog.setIp(ip);
        if (StringUtil.isNotEmpty(ip)) {
            loginLog.setAddress(IPUtils.getArea(ip).getName());
        }
        userLoginLogMapper.insert(loginLog);
    }

    private LoginPo setPerms(Long userId, LoginPo loginPo) {
        LoginPo entity = userLoginLogMapper.selectDevUserInfoByUserId(userId, loginPo.getCompanyId());
        if (Objects.nonNull(entity)) {
            loginPo.setAdminAccount(entity.getAdminAccount());
            loginPo.setCertificationStatus(entity.getCertificationStatus());

            List<String> perms = userMapper.selectPermsListByAdminAccountAndUserId(userId, entity.getAdminAccount(), entity.getCompanyId());
            loginPo.setPerms(perms);
        }
        return loginPo;
    }
}
